﻿using System;
using System.Configuration;

using Rarous.TexyNet.Configuration;
using Rarous.TexyNet.Providers;

using Rhino.Mocks;

using Xunit;

namespace Rarous.TexyNet.Test {
  /// <summary>
  /// This is a test class for TexyTest and is intended
  /// to contain all TexyTest Unit Tests
  /// </summary>
  public class TexyTest : IDisposable {
    private readonly MockRepository _mockery;
    private readonly ITexyProvider _mockedProvider;

    public TexyTest() {
      _mockery = new MockRepository();
      _mockedProvider = _mockery.DynamicMock<ITexyProvider>();
    }

    public void Dispose() {
      _mockery.ReplayAll();
      _mockery.VerifyAll();
    }

    private static ConfigSectionHandler GetConfigHandlerWithDummyProvider() {
      ConfigSectionHandler handler = new ConfigSectionHandler();
      ProviderSettings settings = new ProviderSettings("dummy", typeof(DummyProvider).AssemblyQualifiedName);
      handler.Providers.Add(settings);
      handler.DefaultProvider = "dummy";
      return handler;
    }

    private static ConfigSectionHandler GetConfigWithAllowedClassesAndStyles() {
      ConfigSectionHandler handler = new ConfigSectionHandler();
      StringElement classElement = new StringElement();
      classElement.Name = "important";
      handler.AllowedClasses.Add(classElement);

      StringElement styleElement = new StringElement();
      styleElement.Name = "color";
      handler.AllowedStyles.Add(styleElement);

      return handler;
    }

    [Fact]
    public void Texy_Constructor_Default() {
      Texy target = new Texy();

      Assert.Equal(String.Empty, target.Text);
      Assert.NotNull(target.AllowedClasses);
      Assert.NotNull(target.AllowedStyles);
      Assert.NotNull(target.AllowedTags);
      Assert.NotNull(target.BlockModule);
      Assert.NotNull(target.FormatterModule);
      Assert.NotNull(target.HeadingModule);
      Assert.NotNull(target.ImageDescriptionModule);
      Assert.NotNull(target.ImageModule);
      Assert.NotNull(target.LinkModule);
      Assert.NotNull(target.QuoteModule);
      Assert.NotNull(target.SmiliesModule);
    }

    [Fact]
    public void Texy_Constructor_Text() {
      string text = "text";
      Texy target = new Texy(text);

      Assert.Equal(text, target.Text);
      Assert.NotNull(target.AllowedClasses);
      Assert.NotNull(target.AllowedStyles);
      Assert.NotNull(target.AllowedTags);
      Assert.NotNull(target.BlockModule);
      Assert.NotNull(target.FormatterModule);
      Assert.NotNull(target.HeadingModule);
      Assert.NotNull(target.ImageDescriptionModule);
      Assert.NotNull(target.ImageModule);
      Assert.NotNull(target.LinkModule);
      Assert.NotNull(target.QuoteModule);
      Assert.NotNull(target.SmiliesModule);
    }

    [Fact]
    public void Texy_TrustMode_ShouldSetTrustMode() {
      Texy target = new Texy();
      bool expected = true;
      target.TrustMode = expected;

      Assert.True(target.ObfuscateEmail);
      Assert.True(target.MergeLines);
      Assert.NotNull(target.BlockModule);
    }

    [Fact]
    public void Texy_Version_ShouldReturnVersionFromProvider() {
      Texy target = new Texy();
      target.Provider = _mockedProvider;
      string expected = "1.0 test";
      using (_mockery.Record()) {
        Expect
          .Call(_mockedProvider.Version)
          .Return(expected);
      }

      string actual;
      using (_mockery.Playback()) {
        actual = target.Version;
      }

      Assert.NotNull(actual);
      Assert.Equal(expected, actual);
    }

    [Fact]
    public void Texy_ProcessText_ShouldReturnText() {
      Texy target = new Texy();
      target.Provider = _mockedProvider;
      string expected = "text";

      using (_mockery.Record()) {
        Expect.
          Call(_mockedProvider.Process(null, null)).
          IgnoreArguments().
          Return(expected);
      }

      string actual;
      using (_mockery.Playback()) {
        actual = target.Process();
      }

      Assert.Equal(expected, actual);
    }

    [Fact]
    public void Texy_ProcessNoText_ShouldReturnEmptyString() {
      Texy target = new Texy(null);

      Assert.Equal(null, target.Text);
      Assert.Equal(String.Empty, target.Process());
    }

    [Fact]
    public void Texy_ProcessWithNoProvider_ShouldThrowException() {
      Texy target = new Texy("text");
      target.Provider = null;

      Assert.Throws<NoProviderException>(delegate {
        target.Process();
      });
    }

    [Fact]
    public void Texy_ProcessWithConfiguration_ShouldReturnText() {
      Texy target = new ConfigurableTexy(new ConfigSectionHandler());
      target.Provider = _mockedProvider;
      string expected = "text";

      using (_mockery.Record()) {
        Expect.
          Call(_mockedProvider.Process(null, null)).
          IgnoreArguments().
          Return(expected);
      }

      string actual;
      using (_mockery.Playback()) {
        actual = target.Process();
      }

      Assert.Equal(expected, actual);
    }

    [Fact]
    public void Texy_ProcessWithConfigurationAndDummyProvider_ShouldReturnText() {
      Texy target = new ConfigurableTexy(GetConfigHandlerWithDummyProvider());
      string expected = "text";

      string actual = target.Process();

      Assert.Equal(expected, actual);
    }

    [Fact]
    public void Texy_ProcessWithConfiguredClassesAndStyles_ShouldAddItemsToCollections() {
      Texy target = new ConfigurableTexy(GetConfigWithAllowedClassesAndStyles());

      Assert.Equal(1, target.AllowedClasses.Count);
      Assert.Equal(1, target.AllowedStyles.Count);
    }

    [Fact]
    public void Texy_PreProcessEvent_ShouldFire() {
      Texy target = new ConfigurableTexy(GetConfigHandlerWithDummyProvider());

      bool wasFired = false;
      target.PreProcess += delegate {
        wasFired = true;
      };
      target.Process();

      Assert.True(wasFired);
    }

    [Fact]
    public void Texy_PostProcessEvent_ShouldFire() {
      Texy target = new ConfigurableTexy(GetConfigHandlerWithDummyProvider());

      bool wasFired = false;
      target.PostProcess += delegate {
        wasFired = true;
      };
      target.Process();

      Assert.True(wasFired);
    }
  }

  internal class ConfigurableTexy : Texy {
    public ConfigurableTexy(ConfigSectionHandler config)
      : base("text", config) {
    }
  }

  public class DummyProvider : TexyProvider {
    public override string Version {
      get {
        return "dummy texy";
      }
    }

    public override string Process(string text, ITexySettings settings) {
      return text;
    }
  }
}